<?php

/**
* alltosun.com  tenpay_notify.class.php for newbd
* ============================================================================
* 版权所有 (C) 2009-2014 北京互动阳光科技有限公司，并保留所有权利。
* 网站地址: http://www.alltosun.com
* ----------------------------------------------------------------------------
* 许可声明: 这是一个开源程序，未经许可不得将本软件的整体或任何部分用于商业用途及再发布。
* ============================================================================
* Author: 吴松键 (wusj@alltosun.com)
* Date: 15/1/26 下午5:54
*/

class TenpayNotify {
    /**
     * HTTPS形式消息验证地址
     */
    private $https_verify_url = 'https://gw.tenpay.com/gateway/verifynotifyid.xml';
    private $https_refund_url = 'https://mch.tenpay.com/refundapi/gateway/refund.xml';
    private $https_refund_query_url = 'https://gw.tenpay.com/gateway/normalrefundquery.xml';

    private $tenpay_config;

    private $responseCode;
    private $errInfo;
    private $resContent;
    private $method = 'post';

    function __construct($tenpay_config){
        $this->tenpay_config = $tenpay_config;
    }

    function TenpayNotify($tenpay_config) {
        $this->__construct($tenpay_config);
    }
    /**
     * 针对notify_url验证消息是否是支付宝发出的合法消息
     * @return 验证结果
     */
    function verifyNotify(){
        $param = empty($_POST) ? $_GET : $_POST;
        if(empty($param)) {
            return false;
        } else {
            //生成签名结果
            $isSign = $this->getSignVeryfy($param, $param["sign"]);

            $url = $this->getRequestURL($param, 'verify');
            //获取支付远程服务器ATN结果（验证是否是支付宝发来的消息）
            if ($isSign && $this->getHttpResponsePOST($url)) {
                return true;
            }

            return false;
        }
    }

    public function getResContent()
    {
        return $this->resContent;
    }

    public function getErrInfo()
    {
        return $this->errInfo;
    }

    /**
     * 获取返回时的签名验证结果
     * @param $para_temp 通知返回来的参数数组
     * @param $sign 返回的签名结果
     * @return 签名验证结果
     */
    function getSignVeryfy($param_temp, $sign) {
        //除去待签名参数数组中的空值和签名参数
        $param_filter = openapi_helper::param_filter($param_temp);
        $param_filter['sign_type'] = $param_temp['sign_type'];

        //对待签名参数数组排序
        $param_sort = openapi_helper::param_sort($param_filter);

        //把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
        $prestr = openapi_helper::create_link_string($param_sort);

        $isSgin = false;

        switch (strtoupper(trim($this->tenpay_config['sign_type']))) {
            case "MD5" :
                $isSgin = openapi_helper::md5_verify($prestr, $sign, $this->tenpay_config['key'], 'tenpay');
                break;
            default :
                $isSgin = false;
        }

        return $isSgin;
    }

    /**
     * curl 提交数据
     */
    public function call($param, $type)
    {
        //除去待签名参数数组中的空值和签名参数
        $param_filter = openapi_helper::param_filter($param);

        //对待签名参数数组排序
        $param_sort = openapi_helper::param_sort($param_filter);

        $mysign = openapi_helper::build_request_sign($param_sort, $this->tenpay_config['key'], 'tenpay');
        $param_sort['sign'] = $mysign;

        $url = $this->getRequestURL($param_sort, $type);

        if ($this->getHttpResponsePOST($url)) {
            return true;
        }

        return false;
    }

    /**
     * 远程获取数据，POST模式
     * 注意：
     * 1.使用Crul需要修改服务器中php.ini文件的设置，找到php_curl.dll去掉前面的";"就行了
     * 2.文件夹中cacert.pem是SSL证书请保证其路径有效，目前默认路径是：getcwd().'\\cacert.pem'
     * @param $url 指定URL完整路径地址
     * @param $cacert_url 指定当前工作目录绝对路径
     * @param $para 请求的数据
     * @param $input_charset 编码格式。默认值：空值
     * return 远程输出的数据
     */
    private function getHttpResponsePOST($url) {
        //启动一个CURL会话
        $ch = curl_init();

        // 设置curl允许执行的最长秒数
        curl_setopt($ch, CURLOPT_TIMEOUT, 5);

        // 获取的信息以文件流的形式返回，而不是直接输出。
        curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);

        // 从证书中检查SSL加密算法是否存在
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);

        $arr = explode("?", $url);
        if(count($arr) >= 2 && $this->method == "post") {
            //发送一个常规的POST请求，类型为：application/x-www-form-urlencoded，就像表单提交的一样。
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_URL, $arr[0]);
            //要传送的所有数据
            curl_setopt($ch, CURLOPT_POSTFIELDS, $arr[1]);
        }else{
            curl_setopt($ch, CURLOPT_URL, $url);
        }

        //设置证书信息
        if(isset($this->tenpay_config['user_cert']) && $this->tenpay_config['user_cert'] != "") {
            curl_setopt($ch, CURLOPT_SSLCERT, $this->tenpay_config['user_cert']);
            curl_setopt($ch, CURLOPT_SSLCERTPASSWD, $this->tenpay_config['cert_passwd']);
            curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
        }

        //设置CA
        if(isset($this->tenpay_config['cacart']) && $this->tenpay_config['cacart'] != "") {
            // 对认证证书来源的检查，0表示阻止对证书的合法性的检查。1需要设置CURLOPT_CAINFO
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
            curl_setopt($ch, CURLOPT_CAINFO, $this->tenpay_config['cacart']);
        } else {
            // 对认证证书来源的检查，0表示阻止对证书的合法性的检查。1需要设置CURLOPT_CAINFO
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
        }

        // 执行操作
        $res = curl_exec($ch);
        $this->responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if ($res == NULL) {
            $this->errInfo = "call http err :" . curl_errno($ch) . " - " . curl_error($ch) ;
            curl_close($ch);
            return false;
        } else if($this->responseCode  != "200") {
            $this->errInfo = "call http err httpcode=" . $this->responseCode  ;
            curl_close($ch);
            return false;
        }

        curl_close($ch);
        $this->resContent = $res;

        return true;
    }

    /**
     *获取带参数的请求URL
     */
    private function getRequestURL($param, $type = 'verify') {
        $reqPar = "";
        ksort($param);
        foreach($param as $k => $v) {
            if ($k == 'anu') {
                continue;
            } elseif("spbill_create_ip" != $k ) {
                $reqPar .= $k . "=" . urlencode($v) . "&";
            } else  {
                $reqPar .= $k . "=" . str_replace(".", "%2E", $v) . "&";
            }
        }

        //去掉最后一个&
        $reqPar = substr($reqPar, 0, strlen($reqPar)-1);

        $url = '';
        switch ($type) {
            case 'verify':
                $url = $this->https_verify_url;
                break;
            case 'refund':
                $url = $this->https_refund_url;
                break;
            case 'refund_query':
                $url = $this->https_refund_query_url;
            default:
                break;
        }
        $requestURL = $url . "?" . $reqPar;

        return $requestURL;
    }
}
?>